using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using FireStarterModeller.BO;
using FireStarterModeller.Logic;
using FireStarterModeller.Test.BO;
using Habanero.Base;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using Habanero.BO.Loaders;
using NUnit.Framework;
using XmlLoader=FireStarterModeller.Logic.XmlLoader;

namespace FireStarterModeller.Test.Logic
{
    [TestFixture]
    public class TestXmlLoader
    {
        #region Setup/Teardown
        [TestFixtureSetUp]
        public virtual void TestFixtureSetup()
        {
        }

        [SetUp]
        public virtual void SetupTest()
        {
            ClassDef.ClassDefs.Clear();
            ClassDef.LoadClassDefs(new XmlClassDefsLoader(BOBroker.GetClassDefsXml(), new DtdLoader()));
            TestUtils.WaitForGC();
            BORegistry.DataAccessor = new DataAccessorInMemory();
        }

        [TearDown]
        public virtual void TearDownTest()
        {
        }
        #endregion
        private XmlLoader CreateXmlLoader(string xml)
        {
            return new XmlLoader(new StringReader(xml));
        }

        private string CreateXml(List<IBusinessObject> businessObjects)
        {
            StringBuilder stringBuilder = new StringBuilder();
            XmlPersistor xmlPersistor = new XmlPersistor(new StringWriter(stringBuilder));
            foreach (BusinessObject businessObject in businessObjects)
            {
                xmlPersistor.AddBusinessObject(businessObject);
            }
            xmlPersistor.Persist();
            return stringBuilder.ToString();
        }

        [Test]
        public void TestLoad_EmptyXml()
        {
            //---------------Set up test pack-------------------
            XmlLoader xmlLoader = CreateXmlLoader("");
            //-------------Assert Preconditions -------------
            Assert.AreEqual(0, xmlLoader.BusinessObjects.Count);
            //---------------Execute Test ----------------------
            xmlLoader.Load();
            //---------------Test Result -----------------------
            Assert.AreEqual(0, xmlLoader.BusinessObjects.Count);
        }

        [Test]
        public void TestLoad_OneBo()
        {
            //---------------Set up test pack-------------------
            DMSolution dmSolution = SharedTestUtils.CreateSavedDMSolution();
            string xml = CreateXml(new List<IBusinessObject> { dmSolution });
            XmlLoader xmlLoader = CreateXmlLoader(xml);
            BusinessObjectManager.Instance.ClearLoadedObjects();

            //-------------Assert Preconditions -------------
            Assert.AreEqual(0, xmlLoader.BusinessObjects.Count);
            //---------------Execute Test ----------------------
            xmlLoader.Load();
            //---------------Test Result -----------------------
            Assert.AreEqual(1, xmlLoader.BusinessObjects.Count);
            Assert.IsInstanceOfType(typeof(DMSolution), xmlLoader.BusinessObjects[0]);
            DMSolution loadedDMSolution = (DMSolution)xmlLoader.BusinessObjects[0];
            Assert.IsFalse(loadedDMSolution.Status.IsNew);
            Assert.AreEqual(dmSolution.SolutionName, loadedDMSolution.SolutionName);
            Assert.AreEqual(dmSolution.SolutionDirectory, loadedDMSolution.SolutionDirectory);
        }

        [Test]
        public void TestLoad_TwoBos()
        {
            //---------------Set up test pack-------------------
            DMSolution dmSolution = SharedTestUtils.CreateSavedDMSolution();
            DMClass dmClass = SharedTestUtils.CreateSavedDMClass(dmSolution.DefaultAssembly);
            string xml = CreateXml(new List<IBusinessObject> { dmSolution, dmClass });
            XmlLoader xmlLoader = CreateXmlLoader(xml);
            BusinessObjectManager.Instance.ClearLoadedObjects();

            //-------------Assert Preconditions -------------
            Assert.AreEqual(0, xmlLoader.BusinessObjects.Count);
            //---------------Execute Test ----------------------
            xmlLoader.Load();
            //---------------Test Result -----------------------
            Assert.AreEqual(2, xmlLoader.BusinessObjects.Count);
            Assert.IsInstanceOfType(typeof(DMSolution), xmlLoader.BusinessObjects[0]);
            DMSolution loadedDMSolution = (DMSolution)xmlLoader.BusinessObjects[0];
            Assert.AreEqual(dmSolution.SolutionName, loadedDMSolution.SolutionName);
            Assert.AreEqual(dmSolution.SolutionDirectory, loadedDMSolution.SolutionDirectory);
            Assert.IsInstanceOfType(typeof(DMClass), xmlLoader.BusinessObjects[1]);
            DMClass loadedDMClass = (DMClass)xmlLoader.BusinessObjects[1];
            Assert.AreEqual(dmClass.ClassNameBO, loadedDMClass.ClassNameBO);
            Assert.AreEqual(dmClass.DisplayName, loadedDMClass.DisplayName);
            Assert.AreEqual(dmClass.MappedTableName, loadedDMClass.MappedTableName);
        }

        [Test]
        public void TestLoad_InnerTypedBo()
        {
            //---------------Set up test pack-------------------
            ClassDef classDef = MockBo.InnerMockBo.CreateClassDef();
            ClassDef.ClassDefs.Add(classDef);

            MockBo.InnerMockBo mockBo = new MockBo.InnerMockBo();

            string xml = CreateXml(new List<IBusinessObject> { mockBo });
            XmlLoader xmlLoader = CreateXmlLoader(xml);
            BusinessObjectManager.Instance.ClearLoadedObjects();

            //-------------Assert Preconditions -------------
            Assert.AreEqual(0, xmlLoader.BusinessObjects.Count);
            //---------------Execute Test ----------------------
            xmlLoader.Load();
            //---------------Test Result -----------------------
            Assert.AreEqual(1, xmlLoader.BusinessObjects.Count);
            Assert.IsInstanceOfType(typeof(MockBo), xmlLoader.BusinessObjects[0]);
        }

        [Test]
        public void TestLoad_OneBo_WithDateTimeProp()
        {
            //---------------Set up test pack-------------------
            ClassDef classDef = MockBo.CreateClassDefWithProp<DateTime>();
            ClassDef.ClassDefs.Add(classDef);

            MockBo mockBo = new MockBo();
            mockBo.TestProp = DateTime.Now;

            string xml = CreateXml(new List<IBusinessObject> { mockBo });
            XmlLoader xmlLoader = CreateXmlLoader(xml);
            BusinessObjectManager.Instance.ClearLoadedObjects();

            //-------------Assert Preconditions -------------
            Assert.AreEqual(0, xmlLoader.BusinessObjects.Count);
            //---------------Execute Test ----------------------
            xmlLoader.Load();
            //---------------Test Result -----------------------
            Assert.AreEqual(1, xmlLoader.BusinessObjects.Count);
            Assert.IsInstanceOfType(typeof(MockBo), xmlLoader.BusinessObjects[0]);
            MockBo loadedMockBo = (MockBo)xmlLoader.BusinessObjects[0];
            Assert.AreEqual(mockBo.TestProp, loadedMockBo.TestProp);
            Assert.AreEqual(mockBo.IdProp, loadedMockBo.IdProp);
        }

        [Test]
        public void TestLoad_OneBo_WithIntProp()
        {
            //---------------Set up test pack-------------------
            ClassDef.ClassDefs.Clear();
            ClassDef classDef = MockBo.CreateClassDefWithProp<int>();
            ClassDef.ClassDefs.Add(classDef);

            MockBo mockBo = new MockBo();
            mockBo.TestProp = SharedTestUtils.GetRandomInt(0,1000);

            string xml = CreateXml(new List<IBusinessObject> { mockBo });
            XmlLoader xmlLoader = CreateXmlLoader(xml);
            BusinessObjectManager.Instance.ClearLoadedObjects();

            //-------------Assert Preconditions -------------
            Assert.AreEqual(0, xmlLoader.BusinessObjects.Count);
            //---------------Execute Test ----------------------
            xmlLoader.Load();
            //---------------Test Result -----------------------
            Assert.AreEqual(1, xmlLoader.BusinessObjects.Count);
            Assert.IsInstanceOfType(typeof(MockBo), xmlLoader.BusinessObjects[0]);
            MockBo loadedMockBo = (MockBo)xmlLoader.BusinessObjects[0];
            Assert.AreEqual(mockBo.TestProp, loadedMockBo.TestProp);
            Assert.AreEqual(mockBo.IdProp, loadedMockBo.IdProp);
        }

        [Test]
        public void TestLoad_BoWithEnumProp()
        {
            //---------------Set up test pack-------------------
            ClassDef.ClassDefs.Clear();
            ClassDef classDef = MockBo.CreateClassDefWithProp<MyEnum>();
            ClassDef.ClassDefs.Add(classDef);
            MockBo mockBo = new MockBo();
            mockBo.TestProp = MyEnum.Val2;

            string xml = CreateXml(new List<IBusinessObject> { mockBo });
            XmlLoader xmlLoader = CreateXmlLoader(xml);
            BusinessObjectManager.Instance.ClearLoadedObjects();

            //-------------Assert Preconditions -------------
            Assert.AreEqual(0, xmlLoader.BusinessObjects.Count);
            //---------------Execute Test ----------------------
            xmlLoader.Load();
            //---------------Test Result -----------------------
            Assert.AreEqual(1, xmlLoader.BusinessObjects.Count);
            Assert.IsInstanceOfType(typeof(MockBo), xmlLoader.BusinessObjects[0]);
            MockBo loadedMockBo = (MockBo)xmlLoader.BusinessObjects[0];
            Assert.AreEqual(mockBo.TestProp, loadedMockBo.TestProp);
            Assert.AreEqual(mockBo.IdProp, loadedMockBo.IdProp);
        }
        
        private enum MyEnum
        {
            Val1,
            Val2
        }
    }
}
